#pragma once

#include <cppunit/config/SourcePrefix.h>
#include <iostream>
#include <string>
#include <algorithm>
#include "TestUses.h"
#include "Utilities.h"

void UsesTest::setUp(){
	// procedure 1
	validProcInput.push_back(1);
	validProcInput.push_back(1);

	validVarInput.push_back(2);
	validVarInput.push_back(45);

	validLineInput.push_back(1);
	validLineInput.push_back(1);

	validEntityInput.push_back(Type::Entity::ASSIGNMENT_LINE_ENTITY);
	validEntityInput.push_back(Type::Entity::ASSIGNMENT_LINE_ENTITY);

	// procedure 2
	validProcInput.push_back(2);
	validProcInput.push_back(2);
	validProcInput.push_back(2);
	validProcInput.push_back(2);
	validProcInput.push_back(2);
	validProcInput.push_back(2);
	validProcInput.push_back(2);
	validProcInput.push_back(2);

	validVarInput.push_back(2);
	validVarInput.push_back(45);
	validVarInput.push_back(78);
	validVarInput.push_back(91);
	validVarInput.push_back(123);
	validVarInput.push_back(33);
	validVarInput.push_back(19);
	validVarInput.push_back(67);

	validLineInput.push_back(2);
	validLineInput.push_back(2);
	validLineInput.push_back(2);
	validLineInput.push_back(2);
	validLineInput.push_back(2);
	validLineInput.push_back(3);
	validLineInput.push_back(4);
	validLineInput.push_back(5);

	validEntityInput.push_back(Type::Entity::WHILE_LINE_ENTITY);
	validEntityInput.push_back(Type::Entity::WHILE_LINE_ENTITY);
	validEntityInput.push_back(Type::Entity::WHILE_LINE_ENTITY);
	validEntityInput.push_back(Type::Entity::WHILE_LINE_ENTITY);
	validEntityInput.push_back(Type::Entity::WHILE_LINE_ENTITY);
	validEntityInput.push_back(Type::Entity::IF_LINE_ENTITY);
	validEntityInput.push_back(Type::Entity::WHILE_LINE_ENTITY);
	validEntityInput.push_back(Type::Entity::ASSIGNMENT_LINE_ENTITY);

	// procdure 3
	validProcInput.push_back(3);
	validProcInput.push_back(3);
	validProcInput.push_back(3);
	validProcInput.push_back(3);
	validProcInput.push_back(3);
	validProcInput.push_back(3);
	validProcInput.push_back(3);
	validProcInput.push_back(3);
	validProcInput.push_back(3);
	validProcInput.push_back(3);

	validVarInput.push_back(1);
	validVarInput.push_back(2);
	validVarInput.push_back(45);
	validVarInput.push_back(78);
	validVarInput.push_back(91);
	validVarInput.push_back(23);
	validVarInput.push_back(33);
	validVarInput.push_back(19);
	validVarInput.push_back(67);
	validVarInput.push_back(123);

	validLineInput.push_back(6);
	validLineInput.push_back(6);
	validLineInput.push_back(6);
	validLineInput.push_back(6);
	validLineInput.push_back(6);
	validLineInput.push_back(6);
	validLineInput.push_back(6);
	validLineInput.push_back(6);
	validLineInput.push_back(6);
	validLineInput.push_back(6);

	validEntityInput.push_back(Type::Entity::ASSIGNMENT_LINE_ENTITY);
	validEntityInput.push_back(Type::Entity::ASSIGNMENT_LINE_ENTITY);
	validEntityInput.push_back(Type::Entity::ASSIGNMENT_LINE_ENTITY);
	validEntityInput.push_back(Type::Entity::ASSIGNMENT_LINE_ENTITY);
	validEntityInput.push_back(Type::Entity::ASSIGNMENT_LINE_ENTITY);
	validEntityInput.push_back(Type::Entity::ASSIGNMENT_LINE_ENTITY);
	validEntityInput.push_back(Type::Entity::ASSIGNMENT_LINE_ENTITY);
	validEntityInput.push_back(Type::Entity::ASSIGNMENT_LINE_ENTITY);
	validEntityInput.push_back(Type::Entity::ASSIGNMENT_LINE_ENTITY);
	validEntityInput.push_back(Type::Entity::ASSIGNMENT_LINE_ENTITY);

	// invalid parameters
	invalidVarInput.push_back(0);
	invalidVarInput.push_back(-5);

	nonExistVarInput.push_back(99);
	nonExistVarInput.push_back(44);

	invalidLineInput.push_back(0);
	invalidLineInput.push_back(-1);

	nonExistLineInput.push_back(9);
	nonExistLineInput.push_back(38);

	invalidProcInput.push_back(0);
	invalidProcInput.push_back(-2);

	nonExistProcInput.push_back(19);
	nonExistProcInput.push_back(99);

	invalidEntityInput.push_back(Type::Entity::INVALID_LINE_ENTITY);

	invalidBitMap = Type::Map::Bit(0,Type::List::Bit(0, false));

	usesTb = Uses();
}

void UsesTest::tearDown(){
	validVarInput.clear();
	invalidVarInput.clear();
	nonExistVarInput.clear();

	validLineInput.clear();
	invalidLineInput.clear();
	nonExistLineInput.clear();
}

// Registers the fixture into the 'registry'
CPPUNIT_TEST_SUITE_REGISTRATION( UsesTest );

// method to test the insertion of line, entity, var uses relationship
void UsesTest::testSetLineUses(Type::List::Line lineList, Type::List::LineEntity entityList,
	Type::List::Var varList, bool pass, std::string failMsg){
		Type::Index::Line tmpLine;
		Type::Entity::Line tmpEntity;
		Type::Index::Var tmpVar;
		unsigned int testNumber, t;
		bool tmpTF;

		if(lineList.size() > entityList.size()){
			if(lineList.size() > varList.size()){
				testNumber = lineList.size();
			}else{
				testNumber = varList.size();
			}
		}else{
			if(entityList.size() > varList.size()){
				testNumber = entityList.size();
			}else{
				testNumber = varList.size();
			}
		}

		for(t =0 ; t < testNumber; t++){
			tmpLine = lineList.at(Utilities::getIndexBoundedBySize(t, lineList.size()));
			tmpEntity = entityList.at(Utilities::getIndexBoundedBySize(t, entityList.size()));
			tmpVar = varList.at(Utilities::getIndexBoundedBySize(t, varList.size()));

			tmpTF = usesTb.setLineUses(tmpLine, tmpEntity, tmpVar);

			if(!pass){
				tmpTF = !tmpTF;
			}

			CPPUNIT_ASSERT_ASSERTION_PASS_MESSAGE(failMsg, CPPUNIT_ASSERT(tmpTF));
		}
}

// method to test the insertion of proc, var uses relationship
void UsesTest::testSetProcUses(Type::List::Proc procList, Type::List::Var varList, 
	bool pass, std::string failMsg){
		Type::Index::Proc tmpProc;
		Type::Index::Var tmpVar;
		unsigned int testNumber, t;
		bool tmpTF;

		if(procList.size() > varList.size()){
			testNumber = procList.size();
		}else{
			testNumber = varList.size();
		}

		for(t =0 ; t < testNumber; t++){
			tmpProc = procList.at(Utilities::getIndexBoundedBySize(t, procList.size()));
			tmpVar = varList.at(Utilities::getIndexBoundedBySize(t, varList.size()));

			tmpTF = usesTb.setProcUses(tmpProc, tmpVar);

			if(!pass){
				tmpTF = !tmpTF;
			}

			CPPUNIT_ASSERT_ASSERTION_PASS_MESSAGE(failMsg, CPPUNIT_ASSERT(tmpTF));
		}
}

// method to test the insertion of line, variable uses relationship in bitmap form
void UsesTest::testSetLineBitMap(Type::Map::Bit bitmap, bool pass, std::string failMsg){
	bool tmpTF;

	tmpTF = usesTb.setLineUsesBitMap(bitmap);

	if(!pass){
		tmpTF = !tmpTF;
	}

	CPPUNIT_ASSERT_ASSERTION_PASS_MESSAGE(failMsg, CPPUNIT_ASSERT(tmpTF));
}

// method to test the insertion of procedure, variable uses relationship in bitmap form
void UsesTest::testSetProcBitMap(Type::Map::Bit bitmap, bool pass, std::string failMsg){
	bool tmpTF;

	tmpTF = usesTb.setProcUsesBitMap(bitmap);

	if(!pass){
		tmpTF = !tmpTF;
	}

	CPPUNIT_ASSERT_ASSERTION_PASS_MESSAGE(failMsg, CPPUNIT_ASSERT(tmpTF));
}

// method to test the retrieval of lines using variable
void UsesTest::testGetLinesUse(Type::Index::Var var, Type::Entity::Line entity, bool isEntityPresent,
	Type::List::Line lineList, std::string failMsg){
		Type::List::Line tmpLineList, bufLineList;
		Type::Index::Line bufLine;
		unsigned int t;
		bool tmpTF;

		if(!isEntityPresent){
			tmpLineList = usesTb.getLinesUse(var);
		}else{
			tmpLineList = usesTb.getLinesUse(var,entity);
		}

		tmpTF = lineList.size() == tmpLineList.size();

		CPPUNIT_ASSERT_ASSERTION_PASS_MESSAGE(failMsg + " (size different)", 
			CPPUNIT_ASSERT(tmpTF));

		for(t = 0; t< lineList.size();t++){
			bufLine = lineList.at(t);

			bufLineList = Utilities::removeElementFromList(tmpLineList, bufLine, true);
			tmpTF = bufLineList.size() < tmpLineList.size();
			CPPUNIT_ASSERT_ASSERTION_PASS_MESSAGE(failMsg + " (missing line)", 
				CPPUNIT_ASSERT(tmpTF));

			tmpLineList = bufLineList;
		}

		CPPUNIT_ASSERT_ASSERTION_PASS_MESSAGE(failMsg + " (extra line)", 
			CPPUNIT_ASSERT(tmpLineList.empty()));
}

// method to test the retrieval of procedures using variable
void UsesTest::testGetProcsUse(Type::Index::Var var, Type::List::Proc procList, std::string failMsg){
	Type::List::Proc tmpProcList, bufProcList;
	Type::Index::Proc bufProc;
	unsigned int t;
	bool tmpTF;

	tmpProcList = usesTb.getProcsUse(var);

	tmpTF = procList.size() == tmpProcList.size();

	CPPUNIT_ASSERT_ASSERTION_PASS_MESSAGE(failMsg + " (size different)", 
		CPPUNIT_ASSERT(tmpTF));

	for(t = 0; t< procList.size();t++){
		bufProc = procList.at(t);

		bufProcList = Utilities::removeElementFromList(tmpProcList, bufProc, true);
		tmpTF = bufProcList.size() < tmpProcList.size();
		CPPUNIT_ASSERT_ASSERTION_PASS_MESSAGE(failMsg + " (missing procedure)", 
			CPPUNIT_ASSERT(tmpTF));

		tmpProcList = bufProcList;
	}

	CPPUNIT_ASSERT_ASSERTION_PASS_MESSAGE(failMsg + " (extra procedure)", 
		CPPUNIT_ASSERT(tmpProcList.empty()));
}

// method to test the retrieval of variables using line
void UsesTest::testGetUsedByLine(Type::Index::Line line, Type::List::Var varList, std::string failMsg){
	Type::List::Var tmpVarList, bufVarList;
	Type::Index::Var bufVar;
	unsigned int t;
	bool tmpTF;

	tmpVarList = usesTb.getUsedVarsByLine(line);

	tmpTF = varList.size() == tmpVarList.size();

	CPPUNIT_ASSERT_ASSERTION_PASS_MESSAGE(failMsg + " (size different)", 
		CPPUNIT_ASSERT(tmpTF));

	for(t = 0; t< varList.size();t++){
		bufVar = varList.at(t);

		bufVarList = Utilities::removeElementFromList(tmpVarList, bufVar, true);
		tmpTF = bufVarList.size() < tmpVarList.size();
		CPPUNIT_ASSERT_ASSERTION_PASS_MESSAGE(failMsg + " (missing line)", 
			CPPUNIT_ASSERT(tmpTF));

		tmpVarList = bufVarList;
	}

	CPPUNIT_ASSERT_ASSERTION_PASS_MESSAGE(failMsg + " (extra line)", 
		CPPUNIT_ASSERT(tmpVarList.empty()));
}

// method to test the retrieval of variables using proc
void UsesTest::testGetUsedByProc(Type::Index::Proc proc, Type::List::Var varList, std::string failMsg){
	Type::List::Var tmpVarList, bufVarList;
	Type::Index::Var bufVar;
	unsigned int t;
	bool tmpTF;

	tmpVarList = usesTb.getUsedVarsByProc(proc);

	tmpTF = varList.size() == tmpVarList.size();

	CPPUNIT_ASSERT_ASSERTION_PASS_MESSAGE(failMsg + " (size different)", 
		CPPUNIT_ASSERT(tmpTF));

	for(t = 0; t< varList.size();t++){
		bufVar = varList.at(t);

		bufVarList = Utilities::removeElementFromList(tmpVarList, bufVar, true);
		tmpTF = bufVarList.size() < tmpVarList.size();
		CPPUNIT_ASSERT_ASSERTION_PASS_MESSAGE(failMsg + " (missing procedure)", 
			CPPUNIT_ASSERT(tmpTF));

		tmpVarList = bufVarList;
	}

	CPPUNIT_ASSERT_ASSERTION_PASS_MESSAGE(failMsg + " (extra procedure)", 
		CPPUNIT_ASSERT(tmpVarList.empty()));
}

// method to test the line, variable uses relationship
void UsesTest::testIsLineUses(Type::Index::Line line, Type::List::Var varList, bool pass, std::string failMsg){
	Type::Index::Var tmpVar;
	unsigned int t;
	bool tmpTF;

	for(t=0; t<varList.size(); t++){
		tmpVar = varList.at(t);

		tmpTF = usesTb.isLineUses(line, tmpVar);

		if(!pass){
			tmpTF = !tmpTF;
		}

		CPPUNIT_ASSERT_ASSERTION_PASS_MESSAGE(failMsg, CPPUNIT_ASSERT(tmpTF));
	}
}

// method to test the procedure, variable uses relationship
void UsesTest::testIsProcUses(Type::Index::Proc proc, Type::List::Var varList, bool pass, std::string failMsg){
	Type::Index::Var tmpVar;
	unsigned int t;
	bool tmpTF;

	for(t=0; t<varList.size(); t++){
		tmpVar = varList.at(t);

		tmpTF = usesTb.isProcUses(proc, tmpVar);

		if(!pass){
			tmpTF = !tmpTF;
		}

		CPPUNIT_ASSERT_ASSERTION_PASS_MESSAGE(failMsg, CPPUNIT_ASSERT(tmpTF));
	}
}

// method to test the existence of line-variable and procedure-variable uses relationship
void UsesTest::testIsExists(Type::List::Line lineList, Type::List::Proc procList, Type::List::Var varList, 
	bool pass, std::string failMsg){
		Type::Index::Line tmpLine;
		Type::Index::Proc tmpProc;
		Type::Index::Var tmpVar;
		unsigned int t;
		bool tmpTF;

		for(t =0 ; t < lineList.size(); t++){
			tmpLine = lineList.at(t);
			tmpTF = usesTb.isLineExistsInVar(tmpLine);

			if(!pass){
				tmpTF = !tmpTF;
			}

			CPPUNIT_ASSERT_ASSERTION_PASS_MESSAGE(
				failMsg + " (line existence)" ,CPPUNIT_ASSERT(tmpTF));
		}

		for(t =0 ; t < procList.size(); t++){
			tmpProc = procList.at(t);
			tmpTF = usesTb.isProcExistsInVar(tmpProc);

			if(!pass){
				tmpTF = !tmpTF;
			}

			CPPUNIT_ASSERT_ASSERTION_PASS_MESSAGE(
				failMsg + " (procedure existence)" ,CPPUNIT_ASSERT(tmpTF));
		}

		for(t =0 ; t < varList.size(); t++){
			tmpVar = varList.at(t);
			tmpTF = usesTb.isVarExistsInLine(tmpVar);

			if(!pass){
				tmpTF = !tmpTF;
			}

			CPPUNIT_ASSERT_ASSERTION_PASS_MESSAGE(
				failMsg + " (variable existence in line)" ,CPPUNIT_ASSERT(tmpTF));

			tmpTF = usesTb.isVarExistsInProc(tmpVar);

			if(!pass){
				tmpTF = !tmpTF;
			}

			CPPUNIT_ASSERT_ASSERTION_PASS_MESSAGE(
				failMsg + " (variable existence in procedure)" ,CPPUNIT_ASSERT(tmpTF));
		}
}

void UsesTest::testSetUses(){
	std::cout<<std::endl<<"Uses SetUses()"<<std::endl;

	// verify the insertion of line uses relationship with 
	// invalid line and valid entity, variable will always return false
	msg = "Failed at setting line uses relationship with invalid line, valid entity & variable";
	testSetLineUses(invalidLineInput, validEntityInput, validVarInput, false, msg);

	// verify the insertion of line uses relationship with 
	// invalid entity and valid line, variable will always return false
	msg = "Failed at setting line uses relationship with invalid entity, valid line & variable";
	testSetLineUses(validLineInput, invalidEntityInput, validVarInput, false, msg);

	// verify the insertion of line uses relationship with 
	// invalid variable and valid line, entity will always return false
	msg = "Failed at setting line uses relationship with invalid variable, valid line & entity";
	testSetLineUses(validLineInput, validEntityInput, invalidVarInput, false, msg);

	// verify the insertion of line uses relationship with 
	// valid line, entity, variable will always return true
	msg = "Failed at setting line uses relationship with valid line, entity, variable";
	testSetLineUses(validLineInput, validEntityInput, validVarInput, true, msg);

	// verify the insertion of line uses relationship with 
	// repeating valid line, entity, variable will always return false
	msg = "Failed at setting line uses relationship with valid repeating valid line, entity, variable";
	testSetLineUses(validLineInput, validEntityInput, validVarInput, false, msg);

	// verify the insertion of procedure uses relationship with 
	// invalid procedure and valid variable will always return false
	msg = "Failed at setting procedure uses relationship with invalid proc, valid variable";
	testSetProcUses(invalidProcInput, validVarInput, false, msg);

	// verify the insertion of procedure uses relationship with 
	// valid procedure and invalid variable will always return false
	msg = "Failed at setting procedure uses relationship with valid proc, invalid variable";
	testSetProcUses(validProcInput, invalidVarInput, false, msg);

	// verify the insertion of procedure uses relationship with 
	// valid procedure, valid variable will always return true
	msg = "Failed at setting procedure uses relationship with valid proc, variable";
	testSetProcUses(validProcInput, validVarInput, true, msg);

	// verify the insertion of procedure uses relationship with 
	// valid repeating procedure, valid variable will always return false
	msg = "Failed at setting procedure uses relationship with valid repeating proc, variable";
	testSetProcUses(validProcInput, validVarInput, false, msg);
}

void UsesTest::testSetBitMap(){
	std::cout<<std::endl<<"Uses SetBitMap()"<<std::endl;

	// verify the insertion of invalid bitmap for line will always return false
	msg = "Failed at setting invalid bitmap for line";
	testSetLineBitMap(invalidBitMap, false, msg);

	// verify the insertion of invalid bitmap for proc will always return false
	msg = "Failed at setting invalid bitmap for proc";
	testSetProcBitMap(invalidBitMap, false, msg);

	setupLineProcBitMap();

	// verify the insertion of valid bitmap for line will always return true
	msg = "Failed at setting valid bitmap for line";
	testSetLineBitMap(validLineBitMap, true, msg);

	// verify the insertion of valid bitmap for proc will always return true
	msg = "Failed at setting valid bitmap for proc";
	testSetProcBitMap(validProcBitMap, true, msg);
}

void UsesTest::testGetUses(){
	std::cout<<std::endl<<"Uses GetUses()"<<std::endl;

	Type::List::Line tmpLineList, bufLineList;
	Type::List::Var bufVarList;
	Type::List::Proc bufProcList;
	Type::Index::Var tmpVar;
	Type::Entity::Line tmpEntity;
	unsigned int t;

	testSetUses();

	// verify lines retrival of valid variable will always correct;
	bufVarList = Utilities::copyListWithoutDuplicates(validVarInput);
	msg = "Failed at getting lines that use the valid variable";
	for(t =0 ; t < bufVarList.size(); t++){
		tmpVar = bufVarList.at(t);

		bufLineList = Utilities::copyListWithValueInSource(validVarInput, tmpVar, validLineInput);
		bufLineList = Utilities::copyListWithoutDuplicates(bufLineList);

		testGetLinesUse(tmpVar, Type::Entity::INVALID_LINE_ENTITY, false, bufLineList, msg);
	}

	msg = "Failed at getting lines that use valid variable with given entity";
	for(t =0 ; t < validVarInput.size(); t++){
		tmpVar = validVarInput.at(t);
		tmpEntity = validEntityInput.at(Utilities::getIndexBoundedBySize(t, validEntityInput.size()));

		tmpLineList = Utilities::copyListWithValueInSource(validVarInput, tmpVar, validLineInput);
		bufLineList = Utilities::copyListWithValueInSource(validEntityInput, tmpEntity, validLineInput);
		tmpLineList = Utilities::mergeListWithIntersection(tmpLineList, bufLineList);
		tmpLineList = Utilities::copyListWithoutDuplicates(tmpLineList);

		testGetLinesUse(tmpVar, tmpEntity, true, tmpLineList, msg);
	}

	// verify procedures retrival of valid variable will always correct;
	bufVarList = Utilities::copyListWithoutDuplicates(validVarInput);
	msg = "Failed at getting procedures that use the valid variable";
	for(t =0 ; t < bufVarList.size(); t++){
		tmpVar = bufVarList.at(t);

		bufProcList = Utilities::copyListWithValueInSource(validVarInput, tmpVar, validProcInput);
		bufProcList = Utilities::copyListWithoutDuplicates(bufProcList);

		testGetProcsUse(tmpVar, bufProcList, msg);
	}
}

void UsesTest::testGetUsed(){
	std::cout<<std::endl<<"Uses GetUsed()"<<std::endl;

	Type::List::Line tmpLineList, bufLineList;
	Type::List::Var bufVarList;
	Type::List::Proc bufProcList;
	Type::Index::Line tmpLine;
	Type::Index::Proc tmpProc;
	unsigned int t;

	testSetUses();

	// verify the variables retrieval of valid line will be correct
	bufLineList = Utilities::copyListWithoutDuplicates(validLineInput);
	msg = "Failed at getting all variables used by the valid line";
	for(t =0 ; t < bufLineList.size(); t++){
		tmpLine = bufLineList.at(t);

		bufVarList = Utilities::copyListWithValueInSource(validLineInput, tmpLine, validVarInput);
		bufVarList = Utilities::copyListWithoutDuplicates(bufVarList);

		testGetUsedByLine(tmpLine, bufVarList, msg);
	}
	// verify the variables retrieval of valid line will be correct
	bufLineList = Utilities::copyListWithoutDuplicates(validLineInput);
	msg = "Failed at getting all variables used by the valid line";
	for(t =0 ; t < bufLineList.size(); t++){
		tmpLine = bufLineList.at(t);

		bufVarList = Utilities::copyListWithValueInSource(validLineInput, tmpLine, validVarInput);
		bufVarList = Utilities::copyListWithoutDuplicates(bufVarList);

		testGetUsedByLine(tmpLine, bufVarList, msg);
	}

	// verify the variable retrieval of valid procedure will always be correct
	bufProcList = Utilities::copyListWithoutDuplicates(validProcInput);
	msg = "Failed at getting all variables used by the valid procedure";
	for(t =0 ; t < bufProcList.size(); t++){
		tmpProc = bufProcList.at(t);

		bufVarList = Utilities::copyListWithValueInSource(validProcInput, tmpProc, validVarInput);
		bufVarList = Utilities::copyListWithoutDuplicates(bufVarList);

		testGetUsedByProc(tmpProc, bufVarList, msg);
	}
}

void UsesTest::testIsUses(){
	std::cout<<std::endl<<"Uses IsUses()"<<std::endl;

	testSetUses();

	testIsLineProcUses("Without bit map");

	testSetBitMap();

	testIsLineProcUses("With bit map");
}

void UsesTest::testIsLineProcUses(std::string testMsg){
	Type::List::Line bufLineList;
	Type::List::Proc bufProcList;
	Type::List::Var bufVarList;
	Type::Index::Line tmpLine;
	Type::Index::Proc tmpProc;
	unsigned int t;

	// verify line uses relationship with valid line, variable
	bufLineList = Utilities::copyListWithoutDuplicates(validLineInput);
	msg = "Failed checking line uses with valid line, variable (" + testMsg + ")";
	for(t=0; t<bufLineList.size(); t++){
		tmpLine = bufLineList.at(t);

		bufVarList = Utilities::copyListWithValueInSource(validLineInput, tmpLine, validVarInput);
		bufVarList = Utilities::copyListWithoutDuplicates(bufVarList);

		testIsLineUses(tmpLine, bufVarList, true, msg);
	}

	// verify line uses relationship with valid line, invalid variable
	msg = "Failed checking line uses with valid line, invalid variable (" + testMsg + ")";
	for(t=0; t<bufLineList.size(); t++){
		tmpLine = bufLineList.at(t);

		bufVarList = Utilities::copyListWithValueInSource(validLineInput, tmpLine, invalidVarInput);
		bufVarList = Utilities::copyListWithoutDuplicates(bufVarList);

		testIsLineUses(tmpLine, bufVarList, false, msg);
	}

	// verify line uses relationship with invalid line, valid variable
	bufLineList = Utilities::copyListWithoutDuplicates(invalidLineInput);
	msg = "Failed checking line uses with invalid line, valid variable (" + testMsg + ")";
	for(t=0; t<bufLineList.size(); t++){
		tmpLine = bufLineList.at(t);

		bufVarList = Utilities::copyListWithValueInSource(invalidLineInput, tmpLine, validVarInput);
		bufVarList = Utilities::copyListWithoutDuplicates(bufVarList);

		testIsLineUses(tmpLine, bufVarList, false, msg);
	}

	// verify procedure uses relationship with valid procedure, variable
	bufProcList = Utilities::copyListWithoutDuplicates(validProcInput);
	msg = "Failed checking procedure uses with valid procedure, variable (" + testMsg + ")";
	for(t=0; t<bufProcList.size(); t++){
		tmpProc = bufProcList.at(t);

		bufVarList = Utilities::copyListWithValueInSource(validProcInput, tmpProc, validVarInput);
		bufVarList = Utilities::copyListWithoutDuplicates(bufVarList);

		testIsProcUses(tmpProc, bufVarList, true, msg);
	}

	// verify procedure uses relationship with valid procedure, invalid variable
	bufProcList = Utilities::copyListWithoutDuplicates(validProcInput);
	msg = "Failed checking procedure uses with valid procedure, invalid variable (" + testMsg + ")";
	for(t=0; t<bufProcList.size(); t++){
		tmpProc = bufProcList.at(t);

		bufVarList = Utilities::copyListWithValueInSource(validProcInput, tmpProc, invalidVarInput);
		bufVarList = Utilities::copyListWithoutDuplicates(bufVarList);

		testIsProcUses(tmpProc, bufVarList, false, msg);
	}

	// verify procedure uses relationship with invalid procedure, valid variable
	bufProcList = Utilities::copyListWithoutDuplicates(invalidProcInput);
	msg = "Failed checking procedure uses with invalid procedure, valid variable (" + testMsg + ")";
	for(t=0; t<bufProcList.size(); t++){
		tmpProc = bufProcList.at(t);

		bufVarList = Utilities::copyListWithValueInSource(invalidProcInput, tmpProc, validVarInput);
		bufVarList = Utilities::copyListWithoutDuplicates(bufVarList);

		testIsProcUses(tmpProc, bufVarList, false, msg);
	}
}

void UsesTest::setupLineProcBitMap(){
	/*************************setup bit map*****************************/
	Type::List::Var validVar = Utilities::copyListWithoutDuplicates(validVarInput);
	int varSize = (*std::max_element(validVar.begin(), validVar.end())) + 1;
	Type::Index::Var tmpVar;
	Type::List::Bit tmpVarList;

	// line bit map
	Type::List::Line validLine = Utilities::copyListWithoutDuplicates(validLineInput);
	int lineSize = (*std::max_element(validLine.begin(), validLine.end())) + 1;

	validLineBitMap = Type::Map::Bit(lineSize,Type::List::Bit(varSize, false));
	Type::Index::Line tmpLine;
	for(int i=0; i<validLineInput.size(); i++){
		tmpLine = validLineInput.at(i);
		tmpVarList = validLineBitMap.at(tmpLine);
		tmpVar = validVarInput.at(Utilities::getIndexBoundedBySize(i, validVarInput.size()));

		// update line-variable relationship
		tmpVarList[tmpVar] = true;

		validLineBitMap[tmpLine] = tmpVarList;
	}

	// proc bit map
	Type::List::Proc validProc = Utilities::copyListWithoutDuplicates(validProcInput);
	int procSize = (*std::max_element(validProc.begin(), validProc.end())) + 1;
	validProcBitMap = Type::Map::Bit(procSize,Type::List::Bit(varSize, false));
	Type::Index::Proc tmpProc;
	for(int i=0; i<validProcInput.size(); i++){
		tmpProc = validProcInput.at(i);
		tmpVarList = validProcBitMap.at(tmpProc);
		tmpVar = validVarInput.at(Utilities::getIndexBoundedBySize(i, validVarInput.size()));

		// update procedure-variable relationship
		tmpVarList[tmpVar] = true;

		validProcBitMap[tmpProc] = tmpVarList;
	}
}

void UsesTest::testIsExists(){
	std::cout<<std::endl<<"Uses IsExists()"<<std::endl;

	testSetUses();

	// verify existence of inserted uses relationship with valid line, procedure, variable
	msg = "Failed checking existence of uses relationship with valid line, procedure, variable";
	testIsExists(validLineInput, validProcInput, validVarInput, true, msg);

	// verify existence of uses relationship with invalid line, procedure, variable
	msg = "Failed checking existence of uses relationship with invalid line, procedure, variable";
	testIsExists(invalidLineInput, invalidProcInput, invalidVarInput, false, msg);

	// verify existence of uses relationship with not inserted line, procedure, variable
	msg = "Failed checking existence of uses relationship with not inserted line, procedure, variable";
	testIsExists(nonExistLineInput, nonExistProcInput, nonExistVarInput, false, msg);
}